package com.chorye.datasource.common.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * @Company: 北京XXXX有限公司
 * @Author JiangYy
 * @Title: SlaverDataSourceConfiguration
 * @Description: 从数据源, 不需要配置事务管理器，如果需要配置要配置Atomikos的
 * @Date 2018/12/12 14:21
 */
@Configuration
@MapperScan(basePackages = "com.chorye.datasource.dao.slave", sqlSessionTemplateRef = "slaveSqlSessionTemplate")
public class SlaverDataSourceConfiguration {

    /**
     * 配置从数据源
     */
    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.slave")
    public DataSource dataSource(Environment env) {
        Properties prop = build(env, "spring.datasource.druid.slave.");
        // 创建Atomikos全局事务，所有的事务注册进来
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
        atomikosDataSourceBean.setUniqueResourceName("slaveDataSource");
        atomikosDataSourceBean.setPoolSize(5);
        atomikosDataSourceBean.setXaProperties(prop);
        return atomikosDataSourceBean;
    }

    /**
     * 通过数据源配置从数据源的SqlSessionFactory
     *
     * @param dataSource 从数据源
     * @return sql会话工厂
     * @throws Exception 异常
     */
    @Bean(name = "slaveSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // 指定mapper的位置，指定后，文件夹下必须有xml文件
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml"));
        return bean.getObject();
    }

    /**
     * 通过从数据源的SqlSessionFactory配置从数据源的SqlSessionTemplate
     *
     * @param sqlSessionFactory 从数据源的SqlSessionFactory
     * @return SqlSessionTemplate
     */
    @Bean(name = "slaveSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("slaveSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    /**
     * 设置数据源的配置信息
     *
     * @param env    环境变量
     * @param prefix 配置信息前缀
     * @return
     */
    private Properties build(Environment env, String prefix) {
        Properties prop = new Properties();
        prop.put("driverClassName", env.getProperty(prefix + "driver-class-name", ""));
        prop.put("url", env.getProperty(prefix + "url"));
        prop.put("username", env.getProperty(prefix + "username"));
        prop.put("password", env.getProperty(prefix + "password"));
        prop.put("filters", env.getProperty(prefix + "filters"));
        prop.put("initialSize", env.getProperty(prefix + "initial-size", Integer.class));
        prop.put("maxActive", env.getProperty(prefix + "max-active", Integer.class));
        prop.put("minIdle", env.getProperty(prefix + "min-idle", Integer.class));
        prop.put("maxWait", env.getProperty(prefix + "max-wait", Integer.class));
        prop.put("poolPreparedStatements", env.getProperty(prefix + "pool-prepared-statements", Boolean.class));
        prop.put("maxPoolPreparedStatementPerConnectionSize",
                env.getProperty(prefix + "max-pool-prepared-statement-per-connection-size", Integer.class));
        prop.put("validationQuery", env.getProperty(prefix + "validation-query"));
        prop.put("validationQueryTimeout", env.getProperty(prefix + "validation-query-timeout", Integer.class));
        prop.put("testOnBorrow", env.getProperty(prefix + "test-on-borrow", Boolean.class));
        prop.put("testOnReturn", env.getProperty(prefix + "test-on-return", Boolean.class));
        prop.put("testWhileIdle", env.getProperty(prefix + "test-while-idle", Boolean.class));
        return prop;
    }
}
